﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Reflection;

namespace MossDAL.DotNet
{
    public class SharepointListItem
    {
        /// <summary>
        /// This Method returns an xml string for the ViewFields element of a CAML query.  It will include all fields
        /// and properties that have a SharepointListFieldAttribute attached
        /// </summary>
        /// <returns></returns>
        public virtual string ViewFields()
        {
            StringBuilder sb = new StringBuilder();

            FieldInfo[] finf = this.GetType().GetFields();
            foreach (FieldInfo fi in finf)
            {
                object[] atts = fi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    SharepointListFieldAttribute att = (SharepointListFieldAttribute)atts[0];
                    sb.Append(CamlFactory.CreateFieldRef(att.FieldName));
                }
            }

            PropertyInfo[] propinf = this.GetType().GetProperties();
            foreach (PropertyInfo propi in propinf)
            {

                object[] atts = propi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    SharepointListFieldAttribute att = (SharepointListFieldAttribute)atts[0];
                    sb.Append(CamlFactory.CreateFieldRef(att.FieldName));
                }
            }
            return CamlFactory.CreateViewFields(sb.ToString());
        }    

        /// <summary>
        /// This Method returns an xml string for the ViewFields element of a CAML query.  It will include all fields
        /// and properties that have a SharepointListFieldAttribute attached where the ViewName property of the 
        /// attribute is equal to the viewName parameter.
        /// 
        /// The ViewName property of the SharepointListFieldAttribute allows developers to specify custom views
        /// in SharepointListItem decendants to reduce the amount of data pulled back by the service.  It is 
        /// not necessary to specify this property but that will cause all fields in the SharepointListItem to 
        /// be returned.
        /// </summary>
        /// <param name="viewName">The name of the view in the SharepointListItem.</param>
        /// <returns></returns>
        public virtual string ViewFields(string viewName)
        {
            if (String.IsNullOrEmpty(viewName))
                return ViewFields();

            StringBuilder sb = new StringBuilder();

            FieldInfo[] finf = this.GetType().GetFields();
            foreach (FieldInfo fi in finf)
            {
                object[] atts = fi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    SharepointListFieldAttribute att = (SharepointListFieldAttribute)atts[0];
                    if (att.ViewName == viewName)
                        sb.Append(CamlFactory.CreateFieldRef(att.FieldName));
                }
            }

            PropertyInfo[] propinf = this.GetType().GetProperties();
            foreach (PropertyInfo propi in propinf)
            {

                object[] atts = propi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    SharepointListFieldAttribute att = (SharepointListFieldAttribute)atts[0];
                    if (att.ViewName == viewName)
                        sb.Append(CamlFactory.CreateFieldRef(att.FieldName));
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// This method takes an XElement and loads the data from that element into a SharepointListItem or one 
        /// of its decendant classes.  This is done using the SharepointListFieldAttribute for mapping attributes
        /// of the element to the SharepointListItem with reflection.
        /// </summary>
        /// <param name="element"></param>
        public virtual void Load(XElement element)
        {
            FieldInfo[] finf = this.GetType().GetFields();
            foreach (FieldInfo fi in finf)
            {
                object[] atts = fi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    try
                    {
                        fi.SetValue(this, element.Attribute(((SharepointListFieldAttribute)atts[0]).ServiceFieldName).Value);
                    }
                    catch
                    {
                        if (fi.FieldType == typeof(string) || fi.FieldType == typeof(String))
                            fi.SetValue(this, String.Empty);
                    }
                }
            }

            PropertyInfo[] propinf = this.GetType().GetProperties();
            foreach (PropertyInfo propi in propinf)
            {

                object[] atts = propi.GetCustomAttributes(typeof(SharepointListFieldAttribute), true);
                if (atts.Count() > 0)
                {
                    try
                    {
                        propi.SetValue(this, element.Attribute(((SharepointListFieldAttribute)atts[0]).ServiceFieldName).Value, null);
                    }
                    catch
                    {
                        if (propi.PropertyType == typeof(string) || propi.PropertyType == typeof(String))
                            propi.SetValue(this, String.Empty, null);
                    }
                }
            }
        }
    }
}
